Handling Frame Layout
Parts lay themselves out for display in a document according to the demands of their content and in negotiation with their containing parts. This process takes place through the mechanism of the part's display frames. Methods illustrating how SamplePart handles its display frames are included in this section.SamplePart is a noncontainer part--it does not support embedding of other parts in it--so its frame layout considerations are somewhat simpler than those of container parts. Nonetheless, SamplePart participates in the layout negotiations of its containing part when it is itself embedded in another part. In addition, SamplePart supports multiple display frames, displaying itself in multiple frames and synchronizing those displays as necessary.
The DisplayFrameAdded Method
OpenDoc calls theDisplayFrameAdded
method when a new display frame is created for the part, for example, after the containing part calls the draft'sCreateFrame
method. Generally, in response to theDisplayFrameAdded
call, a part should set itself up to manage the new frame and ensure that it can handle the frame's display requirements.The
SamplePart
object's implementation of theDisplayFrameAdded
method performs the following actions:
Listing 2-9 shows the implementation of the
- Sets up the presentation and view type correctly.
The method checks the new frame's presentation and view type. If the frame's presentation is not the SamplePart main presentation type, the method sets it to be so. If the view type is null, the method sets it to frame view, the most typical preferred type.
- Stores part info data for the new frame.
SamplePart creates aCFrameInfo
object for this purpose and stores a reference to it in the frame's part info field.
- Sets the frame's window disposal flag.
If the frame being added is a root frame, then it has a window associated with it, and the window must be disposed of when the frame is removed. The window disposal flag is checked in SamplePart's internalCleanupWindow
method.
- Updates the part's frame list.
Finally, the method creates a proxy for the new frame and adds a reference to the proxy to its internal display frame list.
DisplayFrameAdded
method.Listing 2-9
DisplayFrameAdded
method
void SamplePart::DisplayFrameAdded( Environment*ev, ODFrame* frame ) { SOM_Trace("SamplePart","DisplayFrameAdded"); if ( frame->GetPresentation(ev) != gGlobals->fMainPresentation ) frame->SetPresentation(ev, gGlobals->fMainPresentation); if ( frame->GetViewType(ev) == kODNullTypeToken ) frame->SetViewType(ev, gGlobals->fFrameView); CFrameInfo* frameInfo = new CFrameInfo; frame->SetPartInfo(ev, (ODInfoType)frameInfo); if ( frame->IsRoot(ev) ) frameInfo->SetShouldDisposeWindow(kODTrue); CFrameProxy* proxy = new CFrameProxy; proxy->InitFrameProxy(ev,frame); fDisplayFrames->Add(proxy); this->SetDirty(ev); }The DisplayFrameConnected Method
OpenDoc calls theDisplayFrameConnected
method if the part is embedded and the containing part reads the display frame into memory, having previously written it to storage. This occurs when the frame becomes visible through scrolling or other actions. OpenDoc calls this method instead ofDisplayFrameAdded
because a new frame is not being created; an existing one is being reconnected to the part.The
SamplePart
object's implementation of theDisplayFrameConnected
method performs the following actions:
Listing 2-10 shows the implementation of the
- Updates the part's frame list.
The method iterates over SamplePart's list of display frames, attempting to match the frame's ID number with the ID numbers of the frame proxies in the list. If there is no match, the method adds the frame. If there is a match, the method updates the proxy's internal fields with information obtained from the frame.
- Ensures that the presentation is meaningful.
The part editor must be able to display the frame, so it must recognize the presentation. In SamplePart's case, the method compares the frame's presentation to the main presentation stored in the globals structure. If it differs, the method sets it to be the main presentation.
- Handles the root frame case.
If the frame is a root frame, the method does two things: it sets the window disposal flag tokODTrue
, and it sets the view type to frame view.
DisplayFrameConnected
method.Listing 2-10
DisplayFrameConnected
method
void SamplePart::DisplayFrameConnected( Environment*ev, ODFrame* frame ) { SOM_Trace("SamplePart","DisplayFrameConnected"); ODBoolean found = kODFalse; CListIterator fiter(fDisplayFrames); for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First(); fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() ) { if ( proxy->GetID() == frame->GetID(ev) ) { proxy->SetFrame(ev,frame); found = kODTrue; } } if ( found ) { if ( frame->GetPresentation(ev) != gGlobals->fMainPresentation ) frame->SetPresentation(ev, gGlobals->fMainPresentation); if ( frame->IsRoot(ev) ) { CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev); frameInfo->SetShouldDisposeWindow(kODTrue); if ( frame->GetViewType(ev) != gGlobals->fFrameView ) frame->SetViewType(ev, gGlobals->fFrameView); } } else { this->DisplayFrameAdded(ev, frame); } }The DisplayFrameRemoved Method
OpenDoc calls a part'sDisplayFrameRemoved
method when its containing part has permanently removed one of the part's display frames. Generally, implementations of theDisplayFrameRemoved
method perform any actions required to remove the frame, including removing frames embedded within the removed frame, relinquishing foci, and updating the part's internal frame list.The
SamplePart
object's implementation of theDisplayFrameRemoved
method performs the following actions:
If any of the preceding actions causes an exception to be thrown, the method catches it in its
- Relinquishes any foci owned by the frame.
The method calls theSamplePart
object's internalRelinquishAllFoci
method, which instantiates a temporary frame object to wrap the reference returned by the arbitrator for each of the foci a SamplePart frame could own: the selection focus and the menu focus. TheRelinquishAllFoci
method compares the focus owner with the frame to be removed, and, if they are equal, relinquishes the focus through the arbitrator and notifies the part that the focus is lost.The
RelinquishAllFoci
method uses theTempODFrame
class, a C++ template class declared in the file TempObj.h, and theODObjectsAreEqual
function, defined in the file ODUtils.h. They are described in Appendix A, "OpenDoc Utilities."
- Cleans up the display frame references.
The method calls theSamplePart
object's internalCleanupDisplayFrame
method. If this frame (that is, the frame to be removed) has a source frame, theCleanupDisplayFrame
method gets a reference to the source frame and to its frame info object. It invalidates the source frame to force it to redraw without any possible effects of having been synchronized with this frame. The method notifies the source frame that it is going away and releases this frame's reference to the source frame (decrementing the source frame's reference count).If this frame is a root frame, then it is in a part window which is being closed, so the
CleanupDisplayFrame
method notifies the source frame that it no longer has a part window. Conversely, if the frame has a part window, the method closes and removes it.If the frame being removed has a dependent frame, the
CleanupDisplayFrame
method notifies it that its source frame is being removed and releases its own reference to the dependent frame.
- Cleans up any window associated with the frame.
The method calls theSamplePart
object's internalCleanupWindow
method, which checks this frame'sShouldDisposeWindow
flag. If the flag is true, the method retrieves references to the frame's OpenDoc window object and its Mac OS platform window structure. It releases the OpenDoc window object, then closes and disposes of the platform window.
- Cleans up the frame and removes it from the part's internal frame list.
The method sets to null its pointer to its frame info object, then deletes the object using theODDeleteObject
utility macro (which is defined in the ODUtils.h file). Finally, the method removes this frame from its internal display frame list and sets the part's dirty flag.
CATCH_ALL
handler, which displays an error dialog box to the user and propagates the error.Listing 2-11 shows the implementation of the
DisplayFrameRemoved
method.Listing 2-11
DisplayFrameRemoved
method
void SamplePart::DisplayFrameRemoved( Environment*ev, ODFrame* frame ) { SOM_Trace("SamplePart","DisplayFrameRemoved"); TRY CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev); this->RelinquishAllFoci(ev, frame); this->CleanupDisplayFrame(ev, frame, kFrameRemoved); this->CleanupWindow(ev, frame); frame->SetPartInfo(ev, (ODInfoType) kODNULL); ODDeleteObject(frameInfo); CListIterator fiter(fDisplayFrames); for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First(); fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() ) { if ( ODObjectsAreEqual(ev, proxy->GetFrame(ev), frame) ) { fiter.RemoveCurrent(); delete proxy; } } this->SetDirty(ev); CATCH_ALL this->DoDialogBox(ev, frame, kErrorBoxID, kErrRemoveFrame); SetErrorCode(kODErrAlreadyNotified); RERAISE; ENDTRY }The DisplayFrameClosed Method
OpenDoc calls theDisplayFrameClosed
method when a frame is closed as a result of the user closing its document. The SamplePart implementation of theDisplayFrameClosed
method is virtually identical to that of itsDisplayFrameRemoved
method except it does not cache runtime information, so it does not set the part's dirty flag. Also, theDisplayFrameClosed
method does not delete the frame proxy object because closed frames may be reconnected before the document is finally closed.Listing 2-12 shows the implementation of the
DisplayFrameClosed
method.Listing 2-12
DisplayFrameClosed
method
void SamplePart::DisplayFrameClosed( Environment*ev, ODFrame* frame ) { SOM_Trace("SamplePart","DisplayFrameClosed"); TRY CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev); this->RelinquishAllFoci(ev, frame); this->CleanupDisplayFrame(ev, frame, kFrameClosed); this->CleanupWindow(ev, frame); frame->SetPartInfo(ev, (ODInfoType) kODNULL); ODDeleteObject(frameInfo); CListIterator fiter(fDisplayFrames); for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First(); fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() ) { if ( proxy->GetID() == frame->GetID(ev) ) { proxy->Purge(ev); } } CATCH_ALL this->DoDialogBox(ev, frame, kErrorBoxID, kErrRemoveFrame); SetErrorCode(kODErrAlreadyNotified); RERAISE; ENDTRY }The AttachSourceFrame Method
OpenDoc calls a part'sAttachSourceFrame
method during creation of a part window from a containing part. That is, if SamplePart is embedded in a frame of another part, and that frame is opened into a part window, the containing part iterates over its embedded frames and adds new corresponding frames in the part window. After each new embedded frame is created, the containing part calls theAttachSourceFrame
method.Listing 2-13 shows the implementation of the
AttachSourceFrame
method.Listing 2-13
AttachSourceFrame
method
void SamplePart::AttachSourceFrame( Environment* ev, ODFrame* frame, ODFrame* sourceFrame ) { SOM_Trace("SamplePart","AttachSourceFrame"); CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev); frameInfo->SetSourceFrame(ev, sourceFrame); frameInfo = (CFrameInfo*) sourceFrame->GetPartInfo(ev); frameInfo->SetDependentFrame(ev, frame); }The FrameShapeChanged Method
OpenDoc calls a part'sFrameShapeChanged
method whenever the part's display frame's shape has been changed, either by the user or by the containing part (if this part is embedded). OpenDoc passes a pointer to the frame whose shape has changed with the method call. The basic responsibility of this method is to update all synchronized frames by propagating the new frame shape to them. To do so, the method finds all the synchronized frames, pointers to which are stored in this frame'sCFrameInfo
object, and calls each frame'sRequestFrameShape
method.Listing 2-14 shows the implementation of the
FrameShapeChanged
method.Listing 2-14
FrameShapeChanged
method
void SamplePart::FrameShapeChanged( Environment* ev, ODFrame* frame ) { SOM_Trace("SamplePart","FrameShapeChanged"); if ( !frame->IsRoot(ev) ) { TempODShape frameShape = frame->AcquireFrameShape(ev, kODNULL); CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev); ODFrame* displayFrame; if ( frameInfo->HasSourceFrame() ) { displayFrame = frameInfo->GetSourceFrame(ev); TempODShape frameShapeCopy = frameShape->Copy(ev); TempODShape returnShape = displayFrame-> RequestFrameShape(ev, frameShapeCopy, kODNULL); displayFrame->Invalidate(ev, kODNULL, kODNULL); } if ( frameInfo->HasDependentFrame() ) { displayFrame = frameInfo->GetDependentFrame(ev); TempODShape frameShapeCopy = frameShape->Copy(ev); TempODShape returnShape = displayFrame-> RequestFrameShape(ev, frameShapeCopy, kODNULL); displayFrame->Invalidate(ev, kODNULL, kODNULL); } } }
Main | Page One | What's New | Apple Computer, Inc. | Find It | Contact Us | Help